#pragma once
#include "onlineUsers.hpp"

typedef enum
{
    UNLOGIN,
    LOGIN
} sstate;

class Session
{
private:
    uint64_t _ssid;            // sessionID
    uint64_t _uid;             // 用户Id
    sstate _state;             // 用户的状态
    wwserver_t::timer_ptr _tp; // session定时器
public:
    Session(uint64_t ssid)
        : _ssid(ssid)
    {
        DLOG("SESSION: %p 被创建!", this);
    }

    ~Session()
    {
        DLOG("SESSION: %p 被销毁!", this);
    }

    // 获取sessionID
    uint64_t get_ssid()
    {
        return _ssid;
    }

    // 设置用户的状态
    void set_user_state(sstate state)
    {
        _state = state;
    }

    // 设置用户ID
    void set_user_id(uint64_t uid)
    {
        _uid = uid;
    }

    // 获取用户id
    uint64_t get_user_id()
    {
        return _uid;
    }

    // 判断是否是登录状态
    bool is_login()
    {
        return _state == LOGIN;
    }

    // 设置定时器
    void set_time_ptr(const wwserver_t::timer_ptr &tp)

    {
        _tp = tp;
    }

    // 获取定时器
    wwserver_t::timer_ptr &get_time_ptr()
    {
        return _tp;
    }
};

#define SESSION_TIMEOUT 30000
#define SESSION_FOREVER -1

// Session的管理
using session_ptr = std::shared_ptr<Session>;

class Session_Manage
{
private:
    uint64_t _next_ssid;
    std::mutex _mutex;
    std::unordered_map<uint64_t, session_ptr> _sessions; // ssid session_ptr
    wwserver_t *_wst;                                    // websocket_server对象用于添加定时器
public:
    Session_Manage(wwserver_t *wst)
        : _next_ssid(1), _wst(wst)
    {
        DLOG("SESSION 管理模块创建完毕!");
    }

    ~Session_Manage()
    {
        DLOG("SESSION 管理模块即将销毁!");
    }

    // 创建session
    session_ptr create_session(uint64_t uid, sstate state)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        session_ptr sp(new Session(_next_ssid)); // 创建一个session
        sp->set_user_id(uid);
        sp->set_user_state(state);
        _sessions.insert(std::make_pair(_next_ssid, sp));
        _next_ssid++;
        return sp;
    }

    // 销毁session（过期）
    void destory_session(uint64_t ssid)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _sessions.erase(ssid); // session_ptr的计数器减到0时，自动释放
    }

    // 获取session
    session_ptr get_session_by_ssid(uint64_t ssid)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        auto it = _sessions.find(ssid);
        if (it == _sessions.end())
        {
            return session_ptr();
        }
        return it->second;
    }

    void append_session(const session_ptr &sp)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _sessions.insert(std::make_pair(sp->get_ssid(), sp));
    }

    // 为session设置过期时间  以秒作为单位
    void set_session_date_time(uint64_t ssid, int sec)
    {
        // 登录之后，创建session，当长时间无任何操作时，自动删除session
        // 当进入游戏大厅，或者游戏房间后，这个session应该永久存在
        // 当退出游戏房间，和游戏大厅后，这个session应该被设置为临时的，一段时间无通信后会被自动删除

        // 通过ssid判断session是否存在
        session_ptr sp = get_session_by_ssid(ssid);
        if (sp.get() == nullptr)
        {
            return;
        }
        // 获取这个session的定时器，并判断
        wwserver_t::timer_ptr wtp = sp->get_time_ptr();
        if (wtp.get() == nullptr && sec == SESSION_FOREVER)
        {
            // 1、session永久存在，设置为永久存在(定时器没有被设置就是永久存在)
            return;
        }
        else if (wtp.get() == nullptr && sec != SESSION_FOREVER)
        {
            // 2、session永久存在，设置为一段时间后自动删除
            wwserver_t::timer_ptr wtp_tmp = _wst->set_timer(sec, std::bind(&Session_Manage::destory_session, this, ssid));
            sp->set_time_ptr(wtp_tmp); // 并设置定时删除
        }
        else if (wtp.get() != nullptr && sec == SESSION_FOREVER)
        {
            // 3、在session被设置了定时删除时，将session设置为永久(为空)
            // 删除定时任务，这个任务会被立即执行
            wtp->cancel();
            // 重新设置任务，并添加session管理
            sp->set_time_ptr(wwserver_t::timer_ptr());
            // 因为这个取消任务，不是立即被执行，所以要确保取消任务被执行完之后，才添加进入session管理中
            _wst->set_timer(0, std::bind(&Session_Manage::append_session, this, sp)); // 依靠wesocket添加定时任务
        }
        else if (wtp.get() != nullptr && sec != SESSION_FOREVER)
        {
            // 4、在session被设置了定时删除时，将session重置删除时间
            // 删除定时任务，这个任务会被立即执行
            wtp->cancel();
            // 重新设置任务，并添加session管理
            sp->set_time_ptr(wwserver_t::timer_ptr());
            // 因为这个取消任务，不是立即被执行，所以要确保取消任务被执行完之后，才添加进入session管理中
            _wst->set_timer(0, std::bind(&Session_Manage::append_session, this, sp)); // 依靠wesocket添加定时任务

            // 给session重新设置定时任务
            wwserver_t::timer_ptr wtp_tmp = _wst->set_timer(sec, std::bind(&Session_Manage::destory_session, this, sp->get_ssid())); // 这个是原来的ssid
            sp->set_time_ptr(wtp_tmp);
        }
    }
};